//
// Created by root on 6/22/17.
//

#include "lib.h"
#include "highlight.h"

/* TODO:
 *  move all indent implementation to gtk_indent.[ch]
 */

/** create application window & initialize values
 *  and connect callback functions. 'app' contains
 *  widgets for window, text_view and statusbar.
 */
GtkWidget *create_window(FunnyWindow *app) {
    GtkAccelGroup *mainaccel;
    GtkWidget *vbox;            /* vbox container   */
    GtkWidget *menubar;         /* menu container   */
    GtkWidget *scrolled_window; /* container for text_view */

    PangoFontDescription *font_desc;
    GtkTextIter iterfirst;
    /* TODO: initialize all values in gtk_appdata.c */
    // app->fontname = g_strdup ("DejaVu Sans Mono 8");
    app->line = 0;          /* initialize beginning pos line/col  */
    app->col = 0;

    app->indent = 0;        /* first non-space/tab char in line   */
    app->indentpl = 0;      /* prev line indent */
    app->indentlevel = 0;   /* will normally be in initialize fn  */
    app->overwrite = FALSE; /* ins/overwrite mode flag */

    GtkWidget *sbalign;         /* alignment for statusbar  */
    guint ptop;                 /* padding, top, bot, l, r  */
    guint pbot;
    guint pleft;
    guint pright;

    /* create toplevel window */
    if (!(app->window = gtk_window_new(GTK_WINDOW_TOPLEVEL))) {
        err_dialog("create_window() gtk_window_new failure.");
        return NULL;
    }
    // gtk_window_set_position (GTK_WINDOW (app->window), GTK_WIN_POS_CENTER);
    gtk_window_set_position(GTK_WINDOW (app->window), GTK_WIN_POS_NONE);
    gtk_window_set_default_size(GTK_WINDOW (app->window), app->winwidth, app->winheight);
    // gtk_window_move (GTK_WINDOW (app->window), app->winrootx, app->winrooty);

    /* create & attach accelerator group */
    mainaccel = gtk_accel_group_new();
    gtk_window_add_accel_group(GTK_WINDOW (app->window), mainaccel);

    /* create vbox to hold menu, scrolled_window & statusbar
     * and add contaier to main window
     */
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER (app->window), vbox);
    // gtk_box_set_spacing (GTK_BOX (vbox), 0);

    /* create menubar and menus to add */
    menubar = create_menubar(app, mainaccel);
    app->menubar = menubar;
    gtk_box_pack_start(GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
    gtk_widget_show(app->menubar);

    /* create toolbar
     * GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT, GTK_TOOLBAR_BOTH, GTK_TOOLBAR_BOTH_HORIZ
     */
    create_toolbar(&(app->toolbar), mainaccel, app);
    gtk_box_pack_start(GTK_BOX(vbox), app->toolbar, FALSE, FALSE, 0);
    gtk_widget_show(app->toolbar);

    /* create buffer for text_view, init cursor and iter, line & col */
    app->buffer = gtk_text_buffer_new(NULL);
    app->cursor = gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(app->buffer));
    gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(app->buffer), &iterfirst,
                                     app->cursor);
    app->line = gtk_text_iter_get_line(&iterfirst);
    app->col = gtk_text_iter_get_line_offset(&iterfirst);

    /* create text_viewview */
    app->view = gtk_text_view_new_with_buffer(app->buffer);
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW (app->view), GTK_WRAP_WORD);
    gtk_text_view_set_left_margin(GTK_TEXT_VIEW (app->view), 5);

    gtk_widget_show(app->view);

    /* Change default font throughout the widget */
    font_desc = pango_font_description_from_string(app->fontname);
    gtk_widget_modify_font(app->view, font_desc);
    /* set tab to lesser of softtab and tabstop if softtab set */
    set_tab_size(font_desc, app, (app->softtab && (app->softtab < app->tabstop) ?
                                  app->softtab : app->tabstop));
    pango_font_description_free(font_desc);

    /* create scrolled_window for view */
    scrolled_window = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled_window),
                                   GTK_POLICY_AUTOMATIC,
                                   GTK_POLICY_AUTOMATIC);

    gtk_container_add(GTK_CONTAINER (scrolled_window), app->view);
    gtk_container_set_border_width(GTK_CONTAINER (scrolled_window), 5);

    gtk_box_pack_start(GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
    gtk_widget_show(scrolled_window);

    /* create/pack statusbar at end within gtk_alignment */
    sbalign = gtk_alignment_new(0, .5, 1, 1);
    gtk_alignment_get_padding(GTK_ALIGNMENT (sbalign), &ptop, &pbot, &pleft, &pright);
    gtk_alignment_set_padding(GTK_ALIGNMENT (sbalign), ptop, pbot + 2, pleft + 5, pright);

    app->statusbar = gtk_statusbar_new();
    status_set_default(app);

    gtk_container_add(GTK_CONTAINER (sbalign), app->statusbar);
    gtk_box_pack_end(GTK_BOX (vbox), sbalign, FALSE, FALSE, 0);

    gtk_widget_show(app->statusbar);
    gtk_widget_show(vbox);

    /* connect all signals */
    g_signal_connect (G_OBJECT(app->window), "delete-event", G_CALLBACK(on_window_delete_event), app);
    g_signal_connect (G_OBJECT(app->window), "destroy", G_CALLBACK(on_window_destroy), NULL);

    /* general */
    g_signal_connect (G_OBJECT(app->view), "key_press_event", G_CALLBACK(on_keypress), app);
    g_signal_connect (app->buffer, "mark_set", G_CALLBACK(on_mark_set), app);
    g_signal_connect (app->buffer, "changed", G_CALLBACK(on_buffer_changed), app);
    g_signal_connect (G_OBJECT(app->view), "toggle-overwrite", G_CALLBACK(on_insmode), app);

    /* set window title */
    gtkwrite_window_set_title(NULL, app);
    gtk_widget_show(app->window);

    /* showall widgets */
    gtk_widget_show_all(app->window);

    /* TODO: load saved settings */
    gtk_widget_set_visible(app->toolbar, app->showtoolbar);
    //gtk_widget_set_sensitive(app->toolbarMenus, app->showtoolbar);

    return app->window;
}

/*
 * window callbacks
 */
gboolean on_window_delete_event(GtkWidget *widget, GdkEvent *event, FunnyWindow *app) {
    /* get window size */
    gtk_window_get_size(GTK_WINDOW (app->window), &(app->winwidth), &(app->winheight));

    /* TODO consolidation with 'quit' - new function ? */
    /* check changed, prompt yes/no */
    buffer_handle_quit(app);

    return FALSE;
}

void on_window_destroy(GtkWidget *widget, FunnyWindow *app) {
    // g_print ("on_window_destroy\n");
    gtk_main_quit();
}

/* function to set the tab width to sz spaces */
void set_tab_size(PangoFontDescription *font_desc, FunnyWindow *app, gint sz) {
    PangoTabArray *tab_array;
    PangoLayout *layout;
    // gchar *tab_string;
    gint width, i;

    // tab_string = g_strdup_printf ("%*s", sz, " ");
    if (app->tabstring) g_free(app->tabstring);
    app->tabstring = g_strdup_printf("%*s", sz, " ");

    // layout = gtk_widget_create_pango_layout (app->view, tab_string);
    layout = gtk_widget_create_pango_layout(app->view, app->tabstring);
    pango_layout_set_font_description(layout, font_desc);
    pango_layout_get_pixel_size(layout, &width, NULL);
    if (width) {
        tab_array = pango_tab_array_new(app->winwidth / width, TRUE);
        for (i = 0; i * width < app->winwidth; i++)
            pango_tab_array_set_tab(tab_array, i, PANGO_TAB_LEFT, i * width);

        gtk_text_view_set_tabs(GTK_TEXT_VIEW(app->view), tab_array);
        pango_tab_array_free(tab_array);
    }

    // g_free (tab_string);
}

void on_insmode(GtkWidget *widget, FunnyWindow *app) {
    if (app->overwrite) {
        app->overwrite = FALSE;
#ifdef DEBUG
        g_print (" toggle-overwrite : overwrite -> insert mode\n");
#endif
    } else {
        app->overwrite = TRUE;
#ifdef DEBUG
        g_print (" toggle-overwrite : insert -> overwrite mode\n");
#endif
    }

    status_set_default(app);   /* update the status bar */
}

void on_mark_set(GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark, FunnyWindow *app) {
    gint line, col;
    gchar *status;

    line = gtk_text_iter_get_line(iter);
    col = gtk_text_iter_get_line_offset(iter);

    // if (line == app->line && col == app->col) return;

    app->line = line;
    app->col = col;

    status = g_strdup_printf(" line:%5d :%4d  |  %s",
                             app->line + 1, app->col + 1,
                             app->overwrite ? "OVR" : "INS");
    status_update_str(app, status);

    g_free(status);
}

void on_buffer_changed(GtkTextBuffer *buffer, FunnyWindow *app) {
    // app->modified = TRUE;
    if (!app->modified)
        gtkwrite_window_set_title(NULL, app);

    highlight(buffer, app);
}

gboolean on_keypress(GtkWidget *widget, GdkEventKey *event, FunnyWindow *app) {

    switch (event->keyval) {
        case GDK_BackSpace:
#ifdef DEBUGKP
            g_print ("  GDK_BackSpace - caught\n");
            g_print ("  app->smartbs: %s\n", app->smartbs ? "TRUE" : "FALSE");
#endif
            if (app->smartbs)   /* smart_backspace in filebuf.c */
                return smart_backspace(app);
            break;              /* or just return FALSE; */
        case GDK_Tab:;      /* catch tab, replace with softtab spaces */
            return smart_tab(app);
        case GDK_Return:
            if (app->indentauto)
                return buffer_indent_auto(app);
            break;
        case GDK_KP_Enter:
            if (app->indentauto)
                return buffer_indent_auto(app);
            break;
        case GDK_Home:
            if (app->smarthe)
                return ((app->kphome = smart_home(app)));
            break;
    }

    app->kphome = FALSE;    /* reset kphome - return above protects needed TRUE */

    return FALSE;
}
